<?php
/**
 * Created by PhpStorm.
 * User: jaylen
 * Date: 2020-04-10
 * Time: 17:51
 */

namespace app\common\service;


class Redis
{
// redis 对象
    protected $redis = null;

    /**
     * 配置参数
     * @var array
     */
    protected $options = [
        'host'       => '127.0.0.1',
        'port'       => 6379,
        'password'   => '',
        'select'     => 0,
        'timeout'    => 0,
        'expire'     => 0,
        'persistent' => false,
        'prefix'     => '',
        'tag_prefix' => 'tag:',
        'serialize'  => [],
    ];

    /**
     * 构架函数
     * Redis constructor.
     * @param array $options    redis参数
     */
    public function __construct(array $options = [])
    {
        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }

        $this->redis = new \Redis;

        if (extension_loaded('redis')) {
            $this->redis = new \Redis;

            if ($this->options['persistent']) {
                $this->redis->pconnect($this->options['host'], (int) $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']);
            } else {
                $this->redis->connect($this->options['host'], (int) $this->options['port'], $this->options['timeout']);
            }

            if ('' != $this->options['password']) {
                $this->redis->auth($this->options['password']);
            }
        } else {
            throw new \BadFunctionCallException('not support: redis');
        }

        if (0 != $this->options['select']) {
            $this->redis->select($this->options['select']);
        }
    }

    /**
     * 返回键名
     * @param string $name redis键名
     * @return string
     */
    public function getRedisKey(string $name): string
    {
        return $this->options['prefix'] . $name;
    }

    /**
     * 将数据插入列表的头部
     * @param string $name redis键名
     * @param $value
     * @return bool|int
     */
    public function lPush(string $name, $value)
    {
        return $this->redis->lPush($this->getRedisKey($name),$value);
    }

    /**
     * 将数据插入列表的尾部
     * @param string $name redis键名
     * @param $value
     * @return bool|int
     */
    public function rPush(string $name, $value)
    {
        return $this->redis->rPush($this->getRedisKey($name),$value);
    }

    /**
     * 返回列表的数据
     * @param string $name  redis键名
     * @param bool $isDelete    读取后是否删除该键
     * @return array
     */
    public function getListData(string $name,bool $isDelete = false): array
    {
        $listData = [];
        $len = $this->redis->lLen($this->getRedisKey($name));
        if (!empty($len) && $len > 0) {
            for ($i = 0; $i < $len; $i++) {
                $listData[] = $this->redis->lIndex($this->getRedisKey($name),$i);
            }
        }

        if ($isDelete) {
            $this->redis->del($this->getRedisKey($name));
        }

        return $listData;
    }

    /**
     * 根据键获取对应的值
     * @param string $name
     * @param string $default
     * @return bool|string
     */
    public function getString(string $name, string $default = '')
    {
        $value = $this->redis->get($this->getRedisKey($name));

        return $value === false ? $default : $value;
    }

    /**
     * 设置字符串键值
     * @param string $name 键
     * @param string $value 值
     * @param int $timeout 超时时间，小于0为永不超时
     * @return bool
     */
    public function setString(string $name,string $value,int $timeout = 0)
    {
        if ($timeout <= 0) {
            return $this->redis->set($this->getRedisKey($name),$value);
        } else {
            return $this->redis->setex($this->getRedisKey($name),$timeout,$value);
        }
    }

    /**
     * 更新字符串键值（如果不存在则按照设定的超时时间再次设定）
     * @param string $name
     * @param string $value
     * @param int $timeout
     * @return bool
     */
    public function updateString(string $name,string $value,int $timeout = 0)
    {
        // 获取对应键的剩余生存时间
        $remainingTime = $this->redis->ttl($this->getRedisKey($name));

        switch ($remainingTime) {
            // 该键设置了永不过期时间
            case '-1' :
                return $this->setString($name,$value,0);
                break;
            // 该键已经过期或者不存在
            case '-2':
                return $this->setString($name,$value,$timeout);
                break;
            default :
                return $this->setString($name,$value,$remainingTime);
                break;
        }
    }

    /**
     * 删除对应键的数据
     * @param string $name
     */
    public function clear(string $name)
    {
        $this->redis->del($this->getRedisKey($name));
    }
}